import pygame
import sys
import time
import math

from Config import Config


class Engine:
    __map = None
    __debug = False
    __window = None
    __stop = False
    __startTime = None
    __stopTime = False
    __success = False

    def __init__(self, theMap, debug=False):
        self.__map = theMap
        self.__debug = debug

    def start(self):
        self.__init()
        self.__startTime = time.time()
        self.__paint()
        while not self.__stop:
            self.__getEvent()
            self.__paint()
            self.__delay()

    @staticmethod
    def __end():
        sys.exit()

    def __getEvent(self):
        eventList = pygame.event.get()
        for event in eventList:
            if event.type == pygame.QUIT:
                self.__end()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    self.__end()
                elif event.key == pygame.K_SPACE:
                    self.__stop = True
            elif event.type == pygame.MOUSEBUTTONDOWN:
                pass
            elif event.type == pygame.MOUSEBUTTONUP:
                self.__onClick(event.pos, event.button)

    def __onClick(self, pos, button):
        cellIndex = self.__coord2Index(pos)
        if not cellIndex:
            return
        cell = self.__map.cell(cellIndex[1], cellIndex[0])
        if button == pygame.BUTTON_LEFT:
            if cell.mined():
                self.__map.clickAll()
                self.__stopTime = time.time()
            else:
                cell.click()
                self.__map.clickEmptyNeighbour(cellIndex[0], cellIndex[1])
        elif button == pygame.BUTTON_RIGHT:
            self.__map.cell(cellIndex[1], cellIndex[0]).mark()

        if not self.__stopTime and self.__map.checkDone():
            self.__stopTime = time.time()
            self.__map.clickAll()
            self.__success = True

        if self.__debug:
            text = 'left' if button == pygame.BUTTON_LEFT else 'right'
            print(cellIndex, '%s button clicked !!!' % text)

    def __paint(self):
        self.__window.fill(Config.GRAY1)

        for y in range(Config.CLIENT_WIDTH):
            for x in range(Config.CLIENT_HEIGHT):
                self.__map.cell(x, y).paint(self.__window)

        for i in range(Config.CLIENT_WIDTH + 1):
            start = [i * Config.CELL_SIZE, 0]
            end = [i * Config.CELL_SIZE, Config.CLIENT_HEIGHT * Config.CELL_SIZE]
            pygame.draw.line(self.__window, Config.GRAY2, start, end, Config.LINE_WIDTH)

        for i in range(Config.CLIENT_HEIGHT + 1):
            start = [0, i * Config.CELL_SIZE]
            end = [Config.CLIENT_WIDTH * Config.CELL_SIZE, i * Config.CELL_SIZE]
            pygame.draw.line(self.__window, Config.GRAY2, start, end, Config.LINE_WIDTH)

        self.__updateStatusBar()

        pygame.display.update()

    def __init(self):
        size = [Config.CELL_SIZE * Config.CLIENT_WIDTH + Config.LINE_WIDTH,
                Config.CELL_SIZE * Config.CLIENT_HEIGHT + Config.LINE_WIDTH + Config.STATUS_BAR_HEIGHT]
        self.__window = pygame.display.set_mode(size)
        pygame.display.set_caption('扫雷大战 1.0')

    @staticmethod
    def __coord2Index(pos):
        x = pos[0] / Config.CELL_SIZE
        y = pos[1] / Config.CELL_SIZE
        if 0 <= x < Config.CLIENT_WIDTH and 0 <= y < Config.CLIENT_HEIGHT:
            return [math.floor(x), math.floor(y)]
        return []

    def __delay(self):
        try:
            time.sleep(0.1)
        except KeyboardInterrupt:
            self.__end()

    def __updateStatusBar(self):
        if self.__stopTime:
            delta = int(self.__stopTime - self.__startTime)
            if self.__success:
                message = '游戏胜利，共用时：%d秒，按空格键重新开始，按ESC键退出' % delta
            else:
                message = '游戏失败，共用时：%d秒，按空格键重新开始，按ESC键退出' % delta
        else:
            now = time.time()
            delta = int(now - self.__startTime)
            message = '游戏进行中，已用时：%d秒，按空格键重新开始，按ESC键退出' % delta

        font = pygame.font.SysFont(Config.GLOBAL_FONT, Config.STATUS_BAR_TXT_SIZE)
        surface = font.render(message, True, Config.BLACK)
        marginTop = int((Config.STATUS_BAR_HEIGHT - surface.get_height()) / 2)
        point = [5, Config.CLIENT_HEIGHT * Config.CELL_SIZE + Config.LINE_WIDTH + marginTop]
        self.__window.blit(surface, point)
